package com.hzhr.iot.device.aop;

import com.hzhr.iot.core.annotation.Author;
import com.hzhr.iot.core.constant.Common_ErrorsEnum;
import com.hzhr.iot.core.constant.HzhrAttrNames;
import com.hzhr.iot.core.constant.HzhrHeaderNames;
import com.hzhr.iot.core.exception.ServiceException;
import com.hzhr.iot.core.util.HzhrStringUtils;
import com.hzhr.iot.core.util.HzhrTypeUtil;
import com.hzhr.iot.device.Global;
import com.hzhr.iot.device.controller.base.BaseController;
import com.hzhr.iot.log.sdk.model.log.LogModel;
import com.hzhr.iot.login.sdk.model.userCard.UserCardModel;
import com.hzhr.iot.login.sdk.service.Login_UserCardService;
import com.hzhr.iot.user.sdk.model.resource.ResourceGetModel;
import com.hzhr.iot.user.sdk.model.resource.ResourceModel;
import com.hzhr.iot.user.sdk.service.User_ResourceService;
import com.hzhr.iot.user.sdk.service.User_UserService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Aspect
@Component
@Order(3)
public class AuthAspect extends BaseController {
    @Autowired
    HttpServletRequest request;
    @Autowired
    User_UserService userService;
    @Autowired
    User_ResourceService resourceService;
    @Autowired
    Login_UserCardService userCardService;

    @Autowired
    Global global;

    @Value("${spring.application.name}")
    String serviceName;
    @Value("${spring.application.version}")
    String version;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Pointcut("execution(* com.hzhr.iot.device.controller..*(..))")
    public void authPointCut() {
    }

    @Before("authPointCut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
    }

    @AfterReturning(returning = "ret", pointcut = "authPointCut()")
    public void doAfterReturning(Object ret) throws Throwable {
    }

    @Around("authPointCut()&&@annotation(author)")
    public Object doAround(ProceedingJoinPoint joinPoint, Author author) throws Throwable {
        LogModel log = (LogModel)request.getAttribute(HzhrAttrNames.LOG);
        if (log == null) {
            throw new ServiceException(Common_ErrorsEnum.COMMON_1);
        }
        try {
            String token = request.getHeader("token");//token
            if (StringUtils.isEmpty(token)) {
                log.appendExceptionInfo(Common_ErrorsEnum.COMMON_2);
                throw new ServiceException(Common_ErrorsEnum.COMMON_2);
            }

            String accessMode = request.getHeader(HzhrHeaderNames.ACCESS_MODE);//访问模式 0 一般 1 全局

            UserCardModel userCard = null;//用户名片

            String userId = request.getHeader(HzhrHeaderNames.USER_ID);//用户编号

            boolean tokenFlag = false;
            String[] tokenSplit = global.getToken().split("_");
            for (String item:
                    tokenSplit) {
                if (item.equals(token)) {
                    tokenFlag = true;
                }
            }

            if (tokenFlag) {//内部调用
                if ("1".equals(accessMode)) {//全局调用，维持原有用户名片
                    userCard = new UserCardModel();
                    userCard.setUserId(Integer.parseInt(userId));
                    userCard.setUserCode(request.getHeader(HzhrHeaderNames.USER_CODE));
                    userCard.setUserName(request.getHeader(HzhrHeaderNames.USER_NAME));
                    userCard.setCompanyId(Integer.parseInt(request.getHeader(HzhrHeaderNames.COMPANY_ID)));
                    userCard.setDeptId(Integer.parseInt(request.getHeader(HzhrHeaderNames.DEPT_ID)));
                    userCard.setType(request.getHeader(HzhrHeaderNames.USER_TYPE));
                } else {
                    if (StringUtils.isEmpty(userId)) {//全局调用，使用系统名片
                        accessMode = "1";
                        userCard = global.getUserCard();
                    } else {//非全局调用
                        userCard = new UserCardModel();
                        userCard.setUserId(Integer.parseInt(request.getHeader(HzhrHeaderNames.USER_ID)));
                        userCard.setUserCode(request.getHeader(HzhrHeaderNames.USER_CODE));
                        userCard.setUserName(request.getHeader(HzhrHeaderNames.USER_NAME));
                        userCard.setCompanyId(Integer.parseInt(request.getHeader(HzhrHeaderNames.COMPANY_ID)));
                        userCard.setDeptId(Integer.parseInt(request.getHeader(HzhrHeaderNames.DEPT_ID)));
                        userCard.setType(request.getHeader(HzhrHeaderNames.USER_TYPE));
                    }
                }
            } else {//外部调用
                Map<String, String> header = new HashMap<>();
                header.put("token", global.getFirstToken());
                userCard = userCardService.getUserCard(header, token, null).getModel();
            }

            if (userCard == null) {
                log.appendExceptionInfo(Common_ErrorsEnum.COMMON_2);
                throw new ServiceException(Common_ErrorsEnum.COMMON_2);
            }

            //验证资源权限
            if (!"1".equals(accessMode) && !"0".equals(userId)) {//如果不是全局用户才验证
                Class clazz = joinPoint.getTarget().getClass();
                Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
                String resourceName = "";
                RequestMapping clazzRm = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
                if (clazzRm != null) {
                    String[] values1 = clazzRm.value();
                    if (values1.length > 0) {
                        String value = values1[0];
                        if (!StringUtils.isEmpty(value)) {
                            resourceName += value.startsWith("/") ? value : "/" + value;
                        }
                    }
                }
                RequestMapping methodRm = method.getAnnotation(RequestMapping.class);
                String[] values2 = methodRm.value();
                if (values2.length > 0) {
                    String value = values2[0];
                    resourceName += value.startsWith("/") ? value : "/" + value;
                }
                boolean checkResult = checkResource(serviceName, version, resourceName, userCard);
                if (!checkResult) {
                    log.appendExceptionInfo(Common_ErrorsEnum.COMMON_2);
                    throw new ServiceException(Common_ErrorsEnum.COMMON_2);
                }
            }

            //验证成功
            request.setAttribute(HzhrHeaderNames.USER_ID, userCard.getUserId());
            request.setAttribute(HzhrHeaderNames.USER_CODE, userCard.getUserCode());
            request.setAttribute(HzhrHeaderNames.USER_NAME, userCard.getUserName());
            request.setAttribute(HzhrHeaderNames.COMPANY_ID, userCard.getCompanyId());
            request.setAttribute(HzhrHeaderNames.DEPT_ID, userCard.getDeptId());
            request.setAttribute(HzhrHeaderNames.USER_TYPE, userCard.getType());
            request.setAttribute(HzhrHeaderNames.ACCESS_MODE, accessMode);

            return joinPoint.proceed();
        } catch (ServiceException e) {
            throw e;
        } catch (Throwable e) {
            log.appendExceptionInfo(e);
            throw new ServiceException(Common_ErrorsEnum.COMMON_0);
        }
    }

    private boolean checkResource(String service, String version, String uri, UserCardModel userCard) throws ServiceException {
        if (userCard == null) return false;
        List<ResourceModel> resourceModelList = null;
        Map<String, Object> query = new HashMap<>();
        query.put("_equal_userId", userCard.getUserId());
        query.put("_show", "list");
        query.put("_show_info", true);
        query.put("_show_mask", true);
        query.put("_is_paging", false);
        Map<String, String> header = new HashMap<>();

        UserCardModel globalUserCard = global.getUserCard();
        header.put("token", global.getFirstToken());
        header.put(HzhrHeaderNames.USER_ID, HzhrTypeUtil.object2string(globalUserCard.getUserId()));
        header.put(HzhrHeaderNames.USER_CODE, HzhrTypeUtil.object2string(globalUserCard.getUserCode()));
        header.put(HzhrHeaderNames.USER_NAME, HzhrTypeUtil.object2string(globalUserCard.getUserName()));
        header.put(HzhrHeaderNames.COMPANY_ID, HzhrTypeUtil.object2string(globalUserCard.getCompanyId()));
        header.put(HzhrHeaderNames.DEPT_ID, HzhrTypeUtil.object2string(globalUserCard.getDeptId()));
        header.put(HzhrHeaderNames.USER_TYPE, HzhrTypeUtil.object2string(globalUserCard.getType()));
        header.put(HzhrHeaderNames.ACCESS_MODE, "1");
        header.put(HzhrHeaderNames.TRANSACTION_ID, HzhrStringUtils.getGUID());
        header.put(HzhrHeaderNames.TRANSACTION_TYPE, "1");
        ResourceGetModel resourceGetModel  = resourceService.get(header, query);
        resourceModelList = resourceGetModel.getModelList();

        String method = request.getMethod();

        boolean result = false;
        for (ResourceModel resourceModel : resourceModelList) {
            String mask = resourceModel.getMask();

            if (uri.equals(resourceModel.getUri()) && version.equals(resourceModel.getVersion()) && service.equals(resourceModel.getService())) {
                if ("POST".equals(method) && mask.charAt(0) == '1') {
                    result = true;
                }
                if ("DELETE".equals(method) && mask.charAt(1) == '1') {
                    result = true;
                }
                if ("PUT".equals(method) && mask.charAt(2) == '1') {
                    result = true;
                }
                if ("PATCH".equals(method) && mask.charAt(3) == '1') {
                    result = true;
                }
                if ("GET".equals(method) && mask.charAt(4) == '1') {
                    result = true;
                }
            }
        }
        return result;
    }
}